package com.pig4cloud.pigx.common.security.mobile;

import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService;
import com.pig4cloud.pigx.common.security.util.PigxSecurityMessageSourceUtil;
import com.pig4cloud.pigx.common.security.util.WebUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.util.Assert;

/**
 * @description: 手机登录校验逻辑
 * {@link org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider}
 * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}
 * @Author 兔子不吃窝边曹
 * @create 2022/8/10 11:39
 **/
@Slf4j
public class MobileAuthenticationProvider implements AuthenticationProvider {

    private MessageSourceAccessor messages = PigxSecurityMessageSourceUtil.getAccessor();

    private UserDetailsChecker detailsChecker = new PigxPreAuthenticationChecks();

    @Getter
    @Setter
    private PigxUserDetailsService userDetailsService;

    @Override
    @SneakyThrows
    public Authentication authenticate(Authentication authentication) {

        String authorization = WebUtils.getRequest().getHeader("Authorization");
        String clientId = WebUtils.extractClientId(authorization).orElseGet(null);
        if (clientId == null) {
            throw new UnapprovedClientAuthenticationException("请求头中client信息为空");
        }

        // 判断
        Assert.isInstanceOf(MobileAuthenticationToken.class, authentication,
                () -> messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.onlySupports",
                        "Only MobileAuthenticationToken is supported"));

        // Determine username
        String mobile = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
                : authentication.getName();


        UserDetails userDetails = userDetailsService.loadUserBySocial(mobile);
        if (userDetails == null) {
            log.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(messages
                    .getMessage("SwitchUserFilter.noCurrentUser", "Noop Bind Account"));
        }

        // 检查账号状态
        detailsChecker.check(userDetails);

        MobileAuthenticationToken authenticationToken = new MobileAuthenticationToken(userDetails,
                userDetails.getAuthorities());
        authenticationToken.setDetails(authentication.getDetails());
        return authenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return MobileAuthenticationToken.class.isAssignableFrom(authentication);
    }

}
